package me.ingxin.android.router.route

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import androidx.activity.result.ActivityResult
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import me.ingxin.android.activitylauncher.launchActivityForResult
import me.ingxin.android.router.Store
import me.ingxin.android.router.annotaions.route.InterceptorMeta
import me.ingxin.android.router.annotaions.route.RouteMeta
import me.ingxin.android.router.utils.Logger
import me.ingxin.android.router.utils.getFragmentActivity
import me.ingxin.android.router.utils.getQuery
import java.util.*


/**
 * Created by ingxin on 2022/4/18
 * @param originRequest 路由请求
 */
class RouteLauncher internal constructor(
    private val originRequest: Request,
    private val context: Context,
    private val lifecycle: Lifecycle?
) {

    private val mainHandler = Handler(Looper.getMainLooper())
    private val routeCallback = originRequest.routeCallback
    private val activityResultCallback = originRequest.activityResultCallback

    fun launch() {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            mainHandler.post { doIntercept() }
        } else {
            doIntercept()
        }
    }

    private fun doIntercept() {
        interceptGlobal(originRequest, object : RouteInterceptor.Dispatcher {
            override fun continueRun() {
                //全局拦截器后不允许重定向
                originRequest.canRedirect = false
                appendExtra(originRequest)
                interceptRelated(originRequest)
            }

            override fun interrupt() {
                routeCallback?.onResult(Result(Result.INTERRUPTED))
            }
        })
    }

    /**
     * 解析uri参数并增加到intent中.
     */
    private fun appendExtra(request: Request) {
        val uri = request.uri
        val map = getQuery(uri.toString())
        for ((key, value) in map) {
            request.putString(key, value)
        }
    }

    /**
     * 路由指定的拦截器
     */
    private fun interceptRelated(request: Request) {
        val path = request.uri.path
        if (path == null) {
            Logger.e("route path is null!")
            routeCallback?.onResult(Result(Result.INVALID_ROUTE))
            return
        }
        val meta = Store.instance.getAllRoute()[path]
        if (meta == null) {
            Logger.e("route path not found")
            routeCallback?.onResult(Result(Result.NOT_FOUND))
            return
        }

        handleRelated(request, meta, object : RouteInterceptor.Dispatcher {
            override fun continueRun() {
                start(request, meta)
            }

            override fun interrupt() {
                routeCallback?.onResult(Result(Result.INTERRUPTED))
            }
        })
    }

    /**
     * 全局的拦截器拦截
     */
    private fun interceptGlobal(request: Request, dispatcher: RouteInterceptor.Dispatcher) {
        val interceptors = Store.instance.getGlobalInterceptor()
        handleNext(interceptors, request, dispatcher)
    }

    /**
     * 指定路由拦截
     */
    private fun handleRelated(
        request: Request,
        meta: RouteMeta,
        dispatcher: RouteInterceptor.Dispatcher
    ) {
        val interceptors = Store.instance.getRelatedInterceptor(meta)
        handleNext(interceptors, request, dispatcher)
    }

    /**
     * 遍历拦截器并依次进行拦截处理
     */
    private fun handleNext(
        interceptors: Queue<InterceptorMeta>,
        request: Request,
        dispatcher: RouteInterceptor.Dispatcher
    ) {
        val interceptorMeta = interceptors.poll()
        if (interceptorMeta == null) {
            dispatcher.continueRun()
            return
        }
        val currentDispatcher = object : RouteInterceptor.Dispatcher {
            override fun continueRun() {
                handleNext(interceptors, request, dispatcher)
            }

            override fun interrupt() {
                Logger.w("interrupted by ${interceptorMeta.destination}")
                dispatcher.interrupt()
            }
        }

        val interceptor = try {
            interceptorMeta.destination.newInstance() as RouteInterceptor
        } catch (ex: Exception) {
            ex.printStackTrace()
            null
        }

        if (interceptor != null) {
            interceptor.handle(context, request, currentDispatcher)
        } else {
            Logger.e("instance ${interceptorMeta.destination.name} failed, ignore this interceptor. see printStackTrace")
            dispatcher.continueRun()
        }

    }

    private fun start(request: Request, meta: RouteMeta) {
        when {
            //activity
            Activity::class.java.isAssignableFrom(meta.destination) ->
                startActivity(request, meta)

            //route handler
            RouteHandler::class.java.isAssignableFrom(meta.destination) ->
                startHandler(request, meta)

            //不支持的类型
            else -> {
                Logger.e("not supported route @${meta.destination.name}")
                routeCallback?.onResult(Result(Result.NOT_SUPPORTED))
            }
        }
    }

    private fun startHandler(request: Request, meta: RouteMeta) {
        val handler = meta.destination.newInstance() as? RouteHandler ?: return
        if (meta.hold && routeCallback != null) {
            Logger.w("hold routeHandler request, developer should call RouteHandler.setResult(Result)")
            val requestKey = RouteHolder.instance.holdHandler(handler, routeCallback)
            lifecycle?.addObserver(KeyLifecycleEventObserver(requestKey, handler))
            handler.handle(context, request)
        } else {
            handler.handle(context, request)
            val result = handler.result ?: Result(Result.NO_RESULT).apply {
                Logger.e("RouteHandler.setResult(Result) is not called")
            }
            routeCallback?.onResult(result)
            handler.onRelease()
        }
    }

    private fun startActivity(request: Request, meta: RouteMeta) {
        //try get fragment activity
        val ctx = context.getFragmentActivity() ?: context

        //如果路由结果需要hold，先缓存起来，并获取requestKey
        val requestKey = if (meta.hold && routeCallback != null) {
            RouteHolder.instance.holdActivity(request, routeCallback)
        } else {
            null
        }

        //set intent
        val intent = Intent(ctx, meta.destination).apply { putExtras(request.extra) }
        if (request.flags != 0) {
            intent.flags = request.flags
        }
        request.action?.let { intent.action = it }
        if (ctx !is Activity) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            Logger.e("current context is ${ctx::class.java.name}, you should use context of activity")
        }

        //start activity
        if (activityResultCallback != null && ctx is FragmentActivity) {
            ctx.launchActivityForResult(intent, request.options) {
                activityResultCallback.onActivityResult(it)
            }
        } else {
            //没有设置数据回调，直接调用startActivity
            ctx.startActivity(intent, request.options?.toBundle())
            activityResultCallback?.let {
                Logger.e("activityResultCallback is ignored, ${ctx::class.java.name} is not FragmentActivity.")
                it.onActivityResult(ActivityResult(Activity.RESULT_CANCELED, null))
            }
        }

        //callback
        if (requestKey != null) {
            Logger.w("hold activity request, developer should call RouteHolder.releaseActivity(Activity,Result)")
            lifecycle?.addObserver(KeyLifecycleEventObserver(requestKey, null))
        } else {
            routeCallback?.onResult(Result())
        }
    }

    private class KeyLifecycleEventObserver(
        private val requestKey: String,
        private var handler: RouteHandler?
    ) : LifecycleEventObserver {
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                //为false表示requestKey已通过其他方式释放了
                val hashKey = RouteHolder.instance.unHold(requestKey)
                source.lifecycle.removeObserver(this)
                if (hashKey) {
                    handler?.onRelease()
                }
                handler = null
            }
        }
    }

}